var __spreadArrays = (this && this.__spreadArrays) || function () {
    for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
    for (var r = Array(s), k = 0, i = 0; i < il; i++)
        for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
            r[k] = a[j];
    return r;
};
var Dep = /** @class */ (function () {
    function Dep() {
        this.subs = []; //存储订阅者，存储传进来的观察者
    }
    Dep.prototype.addSub = function (watcher) {
        this.subs.push(watcher); //存储观察者
    };
    Dep.prototype.notify = function () {
        this.subs.forEach(function (watcher) {
            watcher.update();
        });
    };
    return Dep;
}());
var Watcher = /** @class */ (function () {
    function Watcher(vm, expr, cb) {
        this.vm = vm;
        this.expr = expr;
        this.cb = cb;
        this.oldData = this.get();
    }
    Watcher.prototype.get = function () {
        Dep.target = this;
        var value = ComplieUtil.getVal(this.vm, this.expr);
        Dep.target = null;
        return value;
    };
    Watcher.prototype.update = function () {
        var newVal = ComplieUtil.getVal(this.vm, this.expr);
        if (newVal !== this.oldData) {
            this.cb(newVal);
        }
    };
    return Watcher;
}());
var Observer = /** @class */ (function () {
    function Observer(data) {
        this.observer(data);
    }
    Observer.prototype.observer = function (data) {
        if (data && typeof data === 'object') {
            for (var key in data) {
                this.defineReactive(data, key, data[key]);
            }
        }
    };
    Observer.prototype.defineReactive = function (obj, key, value) {
        var _this = this;
        this.observer(value);
        var dep = new Dep();
        Object.defineProperty(obj, key, {
            get: function () {
                Dep.target && dep.addSub(Dep.target);
                return value;
            },
            set: function (newVal) {
                // console.log(newVal,"newVal")
                if (newVal !== value) {
                    _this.observer(newVal); //补充
                    value = newVal;
                    dep.notify(); //发布功能
                }
            }
        });
    };
    return Observer;
}());
//基类调度
var Complie = /** @class */ (function () {
    function Complie(el, vm) {
        //判断el属性是不是⼀个元素 如果不是元素 那就获取它
        this.el = this.isElementNode(el) ? el : document.querySelector(el); //1
        //保证所有⼈拿到实例vm
        this.vm = vm;
        //把当前节点中的元素放到内存中
        var fragment = this.node2fragment(this.el); //2
        //⽤数据编译模板
        this.compile(fragment); //4
        //把内容塞到⻚⾯中
        this.el.appendChild(fragment); //3
    }
    //判断是不是元素节点
    Complie.prototype.isElementNode = function (node) {
        return node.nodeType === 1;
    };
    //把每个节点都放⼊到内存中
    Complie.prototype.node2fragment = function (node) {
        //创建⼀个⽂档碎⽚
        var fragment = document.createDocumentFragment();
        var firstChild;
        while (firstChild = node.firstChild) {
            //appendChild具有移动性
            fragment.appendChild(firstChild);
        }
        return fragment;
    };
    //核⼼的编译⽅法
    Complie.prototype.compile = function (node) {
        var _this = this;
        var childNodes = node.childNodes;
        __spreadArrays(childNodes).forEach(function (child) {
            //判断是否为节点
            if (_this.isElementNode(child)) {
                // 属性节点方法
                //type="text" v-model="className.name"
                _this.compileElement(child);
                //如果是元素的话 需要传⼊⾃⼰然后遍历⼦节点
                _this.compile(child);
            }
            else {
                //处理文本节点
                //{{className.name}}
                _this.compileText(child);
            }
        });
    };
    //编译元素节点下的属性节点
    //type="text" v-model="className.name"
    Complie.prototype.isDirective = function (attrName) {
        return attrName.startsWith('v-');
    };
    //元素节点 <input type v-model/> <h1> <h3> <ul>
    Complie.prototype.compileElement = function (node) {
        var _this = this;
        var attributes = node.attributes;
        __spreadArrays(attributes).forEach(function (attr) {
            //[type:'text',v-model:'className.name']
            var name = attr.name, expr = attr.value; //重命名
            // console.log(expr)
            if (_this.isDirective(name)) { //v-model: v-html
                var _a = name.split('-'), directive = _a[1];
                // [,directive] = [v,model]
                // [a,b]=[b,a]
                // console.log(directive)
                var directiveName = directive.split(":")[0];
                //这个方法为了复用 代码优化 model
                //对应 129行 <input />
                ComplieUtil[directiveName](node, expr, _this.vm);
            }
        });
    };
    //文本节点
    //{{className.name}}
    Complie.prototype.compileText = function (node) {
        var content = node.textContent;
        // console.log(content)正则表达式 {{className.name}}
        if (/\{\{(.+?)\}\}/.test(content)) {
            //"{{className.name}}"
            ComplieUtil['text'](node, content, this.vm);
        }
    };
    return Complie;
}());
var ComplieUtil = {
    getVal: function (vm, expr) {
        return expr.split('.').reduce(function (data, current) {
            return data[current]; //1707班
        }, vm.$data);
    },
    setVal: function (vm, expr, value) {
        // [className,name]
        expr.split('.').reduce(function (data, current, index, arr) {
            if (index === arr.length - 1) {
                return data[current] = value; //1707班
            }
            return data[current];
        }, vm.$data);
    },
    model: function (node, expr, vm) {
        var _this = this;
        var fn = this.updater['modelUpdater'];
        new Watcher(vm, expr, function (newVal) {
            // 给输入框添加观察者，如果数据更新就会触发这个方法，会拿到新的值
            fn(node, newVal);
        });
        var value = this.getVal(vm, expr);
        fn(node, value);
        node.addEventListener('input', function (e) {
            var value = e.target.value;
            _this.setVal(vm, expr, value);
        });
    },
    text: function (node, expr, vm) {
        var _this = this;
        var fn = this.updater["textUpdater"];
        var value = expr.replace(/\{\{(.+?)\}\}/g, function () {
            var args = [];
            for (var _i = 0; _i < arguments.length; _i++) {
                args[_i] = arguments[_i];
            }
            new Watcher(vm, args[1], function (newVal) {
                fn(node, newVal);
            });
            return _this.getVal(vm, args[1]);
        });
        fn(node, value);
    },
    updater: {
        modelUpdater: function (node, value) {
            node.value = value;
        },
        textUpdater: function (node, value) {
            node.textContent = value;
        }
    }
};
//基类 调度
var Vue = /** @class */ (function () {
    function Vue(options) {
        this.$el = options.el;
        this.$data = options.data;
        //这个跟元素存在
        if (this.$el) {
            //数据劫持  把数据属性转换成访问器属性
            new Observer(this.$data);
            new Complie(this.$el, this);
        }
    }
    return Vue;
}());
